package com.generalbackend.role.filter;

import com.generalbackend.role.enums.AllRoleApiEnum;
import com.generalbackend.role.enums.CommonApiEnum;
import com.generalbackend.role.model.entity.RestApi;
import com.generalbackend.role.service.IRestApiService;
import com.generalbackend.role.util.RoleConf;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static com.generalbackend.common.constants.Constants.MENUS;

/**
 * @author tim.xie
 * @date 2021/12/21 10:39
 */
@Slf4j
@Component
@Order(value = 1)
public class WebApiPermissionFilter implements Filter {

    @Autowired
    private IRestApiService restApiService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = ((HttpServletRequest) servletRequest);
        HttpServletResponse httpResponse = ((HttpServletResponse) servletResponse);
        String requestURI = httpRequest.getRequestURI();
        if (checkApiPermission(httpRequest, httpResponse, filterChain)) {
            return;
        }
        log.warn("非法请求 {}", requestURI);
    }

    private boolean checkApiPermission(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpSession session = request.getSession();
        String uri = request.getRequestURI();
        RestApi restApi = restApiService.selectByApi(uri);
        if (restApi != null && (restApi.getIsCommon().equals(CommonApiEnum.COMMON.code()) || restApi.getIsAll().equals(AllRoleApiEnum.ALL_ROLE.code()))) {
            chain.doFilter(request, response);
            return true;
        }
        List<RestApi> userApi = new ArrayList<>();
        List<String> userMenus = Optional.ofNullable((List<String>) session.getAttribute(MENUS)).orElse(new ArrayList<>());
        List<RestApi> userMenuApi = Optional.ofNullable(restApiService.selectByMenuList(userMenus)).orElse(new ArrayList<>());

        userApi.addAll(userMenuApi);
        userApi.addAll(restApiService.getCommonApi());
        userApi.addAll(restApiService.getAllRoleApi());

        Set<String> apiSet = new HashSet<>();
        if (!userApi.isEmpty()) {
            Iterator<RestApi> iterator = userApi.iterator();
            while (iterator.hasNext()) {
                apiSet.add(iterator.next().getUrl());
            }
        }

        apiSet.addAll(Arrays.asList(RoleConf.getPermissionUrl("allrole").split(",")));
        apiSet.addAll(Arrays.asList(RoleConf.getPermissionUrl("common").split(",")));
        userMenus.forEach(menu -> {
            apiSet.addAll(Arrays.asList(RoleConf.getPermissionUrl(menu).split(",")));
        });

        if (apiInStr(uri, apiSet)) {
            log.info("API校验通过 {}", uri);
            chain.doFilter(request, response);
            return true;
        }
        response.setStatus(HttpStatus.SC_UNAUTHORIZED);
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        response.getOutputStream().write("{\"code\":\"-1\", \"message\":\"非法请求\"}".getBytes(StandardCharsets.UTF_8));
        return false;
    }

    @Override
    public void destroy() {

    }

    public static boolean apiInStr(String uri, Collection<String> apiCollection) {
        for (String api : apiCollection) {
            if (api.contains("*")) {
                int sit = api.indexOf('*');
                String head = api.substring(0, sit);
                String tail = api.substring(sit + 1);
                if (uri.startsWith(head) && uri.contains(tail)) {
                    return true;
                }
            } else {
                if (StringUtils.isNotBlank(api) && uri.startsWith(api)) {
                    return true;
                }
            }
        }
        return false;
    }
}
